home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / deskaccs / remind.asm < prev   
Assembly Source File  |  1986-06-13  |  9KB  |  375 lines

  1. ---------------------------- REMIND.DOC (cut here) ----------------------------
  2. REMIND.COM is a program that can pop up a small reminder on line 25 of
  3. your screen at a given time.  It displays messages via the ROM BIOS, and
  4. thus will work on any IBM BIOS-compatible machine with any display
  5. hardware in any graphics mode.  The syntax is: REMIND time message,
  6. where time is one or two hour digits followed by a colon and two minute
  7. digits.  REMIND can also be entered without any arguments, in which case
  8. the pending, or if none, the previous message is shown.  The program
  9. works by communicating with a resident daemon that steals the timer
  10. interrupt (1c).  This communication is via the multiplex interrupt (2f),
  11. using multiplex number f0.  The daemon is installed as a terminate-and-
  12. stay-resident program the first time that remind is executed.  To run on
  13. a machine with the Microsoft system card, first use the program SETTIME
  14. to correctly set the BIOS timer (DOS's TIME command doesn't do this when
  15. the system card's clock.sys device driver is installed).
  16.  
  17. Written by Robert Lenoil; June/July 1985.
  18. ------------------------ end of REMIND.DOC (cut here) -------------------------
  19.  
  20. ---------------------------- REMIND.ASM (cut here) ----------------------------
  21. ; Displays user-supplied message on 25th screen line at user-specified time.
  22. ; Author: Robert Lenoil        Date: June, 1985
  23.  
  24. ;Placed in the public domain, June 1986.
  25. ;Author's electronic mail address:
  26. ;USENET: lenoil@mit-eddie.uucp            ARPA: lenoil@eddie.mit.edu
  27.  
  28. DOSFN    MACRO    FNUM        ;macro to make DOS function call
  29. IF    FNUM/256
  30.     MOV    AX,FNUM
  31. ELSE
  32.     MOV    AH,FNUM
  33. ENDIF
  34.     INT    21H
  35.     ENDM
  36.  
  37. PRINT    MACRO    TEXT        ;macro to print message at ds:text
  38.     MOV    BX,OFFSET RESGRP:TEXT
  39.     CALL    MSGOUT
  40.     ENDM
  41.  
  42. ATTRIB    EQU    0F0H        ;flashing black foreground, white background
  43.  
  44. BIOSDAT    SEGMENT    AT 40H
  45. ORG    6CH
  46. TIMER_LOW    DW    ?    ;low word of timer count
  47. TIMER_HIGH    DW    ?    ;high word of timer count
  48. TIMER_OFL    DB    ?    ;timer has rolled over since last read
  49. BIOSDAT    ENDS
  50.  
  51. RESGRP    GROUP    DATA,RESDNT,NONRES
  52.  
  53. DATA    SEGMENT
  54. ORG    2CH
  55. ENVSEG    DW    ?        ;seg address of environment
  56. ORG    70H
  57. RINT2F    DD    ?        ;address of next in int2f chain
  58. RINT1C    DD    ?        ;address of real int1c handler
  59. MSGON    DB    ?        ;zero if message already on
  60. MSGLOW    DW    ?        ;when to put up message (in timer ticks)
  61. MSGHIGH    DW    ?
  62. MSG    DW    ?        ;ptr to start of message on command line
  63. MSGLEN    DB    ?        ;message length
  64. CMDLEN    DB    ?        ;command line length
  65. CMD    LABEL    BYTE        ;command line
  66. ORG    100H
  67. DATA    ENDS
  68.  
  69. RESDNT    SEGMENT            ;handle timer interrupt
  70. ASSUME    CS:RESGRP,DS:BIOSDAT
  71.  
  72. ENTRY:    JMP    NEAR PTR START
  73.  
  74. ;note that on entry, caller's AX,DX are saved; DS points to BIOS data area
  75. INT1C:    STI
  76.     SUB    AX,AX
  77.     CMP    MSGON,AL    ;has message already been displayed?
  78.     JE    EXINT        ;yes, exit
  79.     CMP    TIMER_OFL,AL    ;has timer overflowed?
  80.     JNE    EXINT        ;yes, exit (it's after midnight)
  81.     MOV    AX,TIMER_HIGH
  82.     CMP    AX,MSGHIGH
  83.     JB    EXINT
  84.     JA    DISPLAY
  85.     MOV    AX,TIMER_LOW
  86.     CMP    AX,MSGLOW
  87.     JB    EXINT
  88.  
  89. DISPLAY:            ;it's time: print message
  90.     PUSH    BX        ;save regs
  91.     PUSH    CX
  92.     PUSH    DX
  93.     PUSH    BP
  94.     PUSH    SI
  95.     PUSH    DI
  96.  
  97.     MOV    BL,2        ;send two beeps
  98. BEEPLP:    MOV    AX,0E07H
  99.     INT    10H
  100.     DEC    BL
  101.     JNZ    BEEPLP
  102.  
  103.     MOV    AH,15
  104.     INT    10H        ;[BH]=active display page, [AH]=max # columns
  105.     PUSH    AX        ;[AL]=video mode
  106.     MOV    AH,3
  107.     INT    10H        ;[DX] = cursorpos
  108.     POP    AX
  109.     PUSH    DX
  110.     PUSH    AX
  111.     MOV    SI,MSG        ;[SI] = ptr to msg
  112.     MOV    CL,MSGLEN
  113.     SUB    CH,CH        ;[CX] = msg length
  114.     POP    AX
  115.     CMP    CL,AH        ;check if msg longer than screen width
  116.     JLE    DISP1
  117.     XCHG    CL,AH        ;yes, truncate
  118. DISP1:    MOV    BL,ATTRIB    ;load screen attribute
  119.     CMP    AL,4        ;are we in a graphics mode (AL > 3)?
  120.     JB    DISP2
  121.     AND    BL,7FH        ;yes, turn off bit 7 (otherwise characters are
  122.                 ;XORed onto screen, which isn't what we want.)
  123. DISP2:    MOV    DX,1800H    ;set cursorpos to row 24, column 0
  124. DISPLP:    MOV    AH,2        ;set cursorpos
  125.     INT    10H
  126.     MOV    AH,9        ;function = write char/attrib
  127.     MOV    AL,CS:[SI]    ;get character
  128.     PUSH    SI
  129.     PUSH    CX
  130.     MOV    CX,1        ;repeat count of one
  131.     INT    10H        ;write it
  132.     POP    CX
  133.     POP    SI
  134.     INC    SI        ;position to next char
  135.     INC    DX        ;increment cursorpos
  136.     LOOP    DISPLP        ;loop till cx=0
  137.  
  138.     POP    DX        ;restore cursorpos
  139.     MOV    AH,2
  140.     INT    10H
  141.  
  142.     MOV    MSGON,CH    ;set displayed flag
  143.  
  144.     POP    DI        ;pop regs
  145.     POP    SI
  146.     POP    BP
  147.     POP    DX
  148.     POP    CX
  149.     POP    BX
  150.  
  151. EXINT:    JMP    RINT1C        ;jump to real timer tick handler
  152.  
  153. INT2F:    CMP    AH,0F0H        ;if not our number, chain to next
  154.     JE    OUR2F
  155.     JMP    RINT2F
  156.  
  157. OUR2F:    CMP    AL,0        ;is function Get Installed State?
  158.     JE    XINT2F
  159.     PUSH    CS        ;otherwise load our segment into es
  160.     POP    ES
  161. XINT2F:    MOV    AL,0FFH        ;tell caller that we're installed
  162.     IRET
  163. RESDNT    ENDS
  164.  
  165. NONRES    SEGMENT
  166. ASSUME    DS:RESGRP
  167. START:    ;deallocate environment space
  168.     MOV    AX,ENVSEG
  169.     MOV    ES,AX
  170.     DOSFN    49H
  171.  
  172.     ;erase 25th screen line
  173.     MOV    AH,15
  174.     INT    10H        ;[BH]=active display page, [AH]=max # columns
  175.     MOV    BL,AH        ;save ah
  176.     MOV    AH,3
  177.     INT    10H        ;[DX] = cursorpos
  178.     PUSH    DX
  179.     MOV    DX,1800H    ;set cursorpos to row 24, column 0
  180.     MOV    AH,2
  181.     INT    10H
  182.     SUB    CX,CX
  183.     XCHG    BL,CL        ;[CX]=screen width, [BL]=0
  184.     MOV    AH,9        ;write (screen width) chars w/attribute 0
  185.     INT    10H    
  186.     POP    DX        ;restore cursorpos
  187.     MOV    AH,2
  188.     INT    10H
  189.  
  190.     MOV    AX,0F000H    ;perform installation check
  191.     INT    2FH
  192.     CMP    AL,0FFH        ;are we installed?
  193.     JNE    INSTALL
  194.     MOV    AX,0F001H    ;yes, get segment of resdnt in es
  195.     INT    2FH
  196.     XOR    CH,CH        ;reset just-installed flag
  197.     JMP    SHORT PARSE
  198.  
  199. ASSUME    ES:RESGRP
  200. INSTALL:            ;install resident code
  201.     OR    AL,AL        ;can we install?
  202.     JNZ    CANT        ;al != 0; can't install resdnt code
  203.     MOV    MSGON,AL    ;turn off display flag until we're ready
  204.     DOSFN    352FH        ;store address of int2f handler
  205.     MOV    WORD PTR RINT2F,BX
  206.     MOV    BX,ES
  207.     MOV    WORD PTR RINT2F+2,BX
  208.     MOV    DX,OFFSET RESGRP:INT2F    ;set int2f vector to us
  209.     DOSFN    25H
  210.     DOSFN    351CH        ;store address of real int1c handler
  211.     MOV    WORD PTR RINT1C,BX
  212.     MOV    BX,ES
  213.     MOV    WORD PTR RINT1C+2,BX
  214.     MOV    DX,OFFSET RESGRP:INT1C    ;set int1c vector to us
  215.     DOSFN    25H
  216.     PRINT    LOADED
  217.     MOV    CH,1        ;flag that we just installed ourself
  218.  
  219. ;parse command line
  220. PARSE:    SUB    BX,BX
  221.     MOV    CL,CMDLEN
  222.     CALL    EAT_SPACE    ;eat initial whitespace
  223.     JC    GETHRS
  224. ;command line is empty. show pending message
  225.     OR    CH,CH
  226.     JNZ    STAY0        ;just installed ourself; there is no message
  227.     CMP    ES:MSGON,0    ;is there a pending message?
  228.     JE    NOMSG
  229.     PRINT    PENDING        ;yes, print "pending"
  230.     JMP    SHORT PRCMD
  231. NOMSG:    PRINT    LASTMSG        ;no, print "last reminder"
  232. PRCMD:    PUSH    ES        ;get resident segment in ds
  233.     POP    DS
  234.     PRINT    CMD        ;print reminder
  235. EXIT0:    XOR    AL,AL        ;exit with errorlevel = 0
  236. EXIT:    DOSFN    4CH
  237.  
  238. CANT:    PRINT    NOLOAD
  239.     MOV    AH,2
  240.     JMP    SHORT EXIT
  241.  
  242. STAY0:    MOV    AL,0        ;errorlevel = 0
  243. STAY:    MOV    DX,OFFSET RESGRP:START    ;terminate and stay resident
  244.     MOV    CL,4
  245.     SHR    DX,CL
  246.     DOSFN    31H
  247.  
  248. GETHRS:    CALL    GETDIG1
  249.     CMP    CMD[BX],':'
  250.     JE    GOTHRS
  251.     CALL    GETDIG2
  252.     CMP    CMD[BX],':'
  253.     JNE    SYNTAX
  254. GOTHRS:    CMP    AL,24        ;check for range 0-23
  255.     JGE    SYNTAX
  256.     INC    BX        ;skip colon
  257.     MOV    DX,65520
  258.     MUL    DX        ;convert hours to timer ticks
  259.     MOV    MSGHIGH,DX
  260.     MOV    MSGLOW,AX
  261.  
  262.     CALL    GETDIG1        ;get seconds
  263.     CALL    GETDIG2
  264.     CMP    AL,60        ;check for range 0-59
  265.     JGE    SYNTAX
  266.     MOV    DX,1092
  267.     MUL    DX        ;convert to timer ticks
  268.     ADD    MSGLOW,AX    ;and add to hours
  269.     ADC    MSGHIGH,DX
  270.  
  271.     CMP    CMD[BX],20H    ;at least one space required
  272.     JNE    SYNTAX
  273.     CALL    EAT_SPACE    ;consume any others
  274.     JNC    SYNTAX
  275.  
  276.     LEA    AX,CMD[BX]    ;store start of message ptr
  277.     MOV    MSG,AX
  278.     MOV    DL,CL
  279.     SUB    DL,BL        ;store message length
  280.     MOV    MSGLEN,DL
  281.  
  282.     INC    MSGON        ;all fields are setup, set the display flag
  283.  
  284.     OR    CH,CH        ;are we the resident code?
  285.     JNZ    STAY0        ;yes: we're done
  286.     CMP    ES:MSGON,0    ;no: will we overwrite a pending message?
  287.     JE    DWNLD
  288.  
  289.     PUSH    CX        ;yes, print it first
  290.     PRINT    OVRWRT
  291.     PUSH    ES
  292.     POP    DS
  293.     PRINT    CMD
  294.     PUSH    CS
  295.     POP    DS
  296.     POP    CX
  297.  
  298. DWNLD:    STD            ;no: download msg to resident code
  299.     ;we move backwards so that the display flag is the last byte written
  300.     ADD    CL,9
  301.     MOV    SI,OFFSET RESGRP:MSGON - 1
  302.     ADD    SI,CX
  303.     MOV    DI,SI
  304.     REP    MOVSB
  305.     JMP    EXIT0        ;we're done
  306.  
  307. SYNTAX:    PUSH    CX        ;save ch
  308.     PRINT    SERROR
  309.     POP    CX
  310.     MOV    AL,1        ;errorlevel = 1
  311.     OR    CH,CH        ;are we the resident code?
  312.     JNZ    GOSTAY        ;yes, then stay resident
  313.     JMP    EXIT        ;else just exit
  314. GOSTAY:    JMP    STAY
  315.  
  316. EAT_SPACE    PROC    NEAR
  317. ;Advances cmd[bx] past any spaces.  Resets carry if ran off end of cmd.
  318.     CMP    BL,CL
  319.     JNC    ATE
  320.     CMP    CMD[BX],20H
  321.     STC
  322.     JNE    ATE
  323.     INC    BX
  324.     JMP    SHORT EAT_SPACE
  325. ATE:    RET
  326. EAT_SPACE    ENDP
  327.  
  328. GETDIG1    PROC    NEAR
  329. ;GETDIG1 gets digit in AX.  GETDIG2 multiplies AX by 10 and adds new digit.
  330.     SUB    AX,AX
  331. GETDIG2:
  332.     MOV    DL,CMD[BX]
  333.     CMP    DL,'0'        ;check for digit range
  334.     JL    SYNTAX
  335.     CMP    DL,'9'
  336.     JG    SYNTAX
  337.     INC    BX
  338.     SUB    DL,'0'
  339.     MOV    DH,10
  340.     MUL    DH
  341.     ADD    AL,DL
  342.     RET
  343. GETDIG1    ENDP
  344.  
  345. MSGOUT    PROC    NEAR        ;displays string at ds:bx w/length byte at bx-1
  346.     SUB    CH,CH        ;output message to stderr
  347.     MOV    CL,[BX]-1
  348.     MOV    DX,BX
  349.     MOV    BX,2
  350.     DOSFN    40H
  351.     MOV    DL,0DH        ;output CRLF to console
  352.     DOSFN    6H
  353.     MOV    DL,0AH
  354.     INT    21H
  355.     RET
  356. MSGOUT    ENDP
  357.  
  358. ;Messages (each preceeded by a byte holding its length)
  359.     DB    27
  360. SERROR    DB    "Usage: REMIND hh:mm message"
  361.     DB    34
  362. NOLOAD    DB    "System error: Can't install daemon"
  363.     DB    24
  364. LOADED    DB    "REMIND daemon installed."
  365.     DB    8
  366. PENDING    DB    "Pending:"
  367.     DB    35
  368. LASTMSG    DB    "Nothing pending; last reminder was:"
  369.     DB    28
  370. OVRWRT    DB    "Overwriting pending message:"
  371. NONRES    ENDS
  372.  
  373. END    ENTRY
  374. ------------------------ end of REMIND.ASM (cut here) -------------------------
  375.